home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-10-16 | 7.0 KB | 133 lines | [TEXT/GEOL] |
- Item 6238540 13-Oct-89 18:58
-
- From: ALGER Alger, Jeff,VCA
-
- To: D4684 Robins Analytics, S Robins,PRT
- MADA.EUROPE MacApp Dev Assoc Europe, E Carrasco
- AU0008 Kopfwerk EDV SW Entwicklung
- D2086 Efficient Field Svc, C Faith,PRT
-
- cc: MACAPP.TECH$ MACAPP Tech
-
- Sub: Re: MacApp & InsideOut (long)
-
- Doug, Eric, Tommi, Curtis,
-
- Regarding MacApp and InsideOut - I have used this combination now in three
- projects with varying degrees of success. Allow me to propose a slightly
- different slant on the solutions proposed so far to this integration.
-
- My article in the September issue of Frameworks on "TDocument and Databases"
- provides an outline of the architecture, based on classical notions of
- relational database theory: scheme, relation, domain, and tuple. The article
- was generic, not InsideOut-specific, but the techniques actually derive in part
- from my experience with InsideOut. I will summarize the principal points here:
-
- (1) The abstraction of the database consists of classes TRelation, TDomain,
- TAccessMethod, and TTuple. The scheme itself is encapsulated in two instances
- (actually, subclasses) of TRelation: TRelationRelation, which describes all
- relations in the scheme; and TDomainRelation, which describes all domains in
- the scheme. For this reason, no explicit class is needed to represent the
- scheme, just something - TDatabase - which contains references to the RR and DR
- relations. A TAccessMethod maps to an index over an InsideOut "view" (which is
- conceptually a file of records.) A TTuple maps to a specific record in a view.
-
- (2) Each TRelation contains a name (string), a TList of TTuples (more about
- this later) and a TList of TAccessMethods. A TRelation maps to a specific view
- (IO term, not MacApp) of the underlying database.
-
- (3) Records are retrieved and queries specified using the class TCursor. The
- steps to follow are these:
- (a) Ask TDatabase to get you the right TRelation instance.
- (b) Ask the TRelation instance to give you a fresh TCursor.
- (c) Build the query in the TCursor (see below).
- (d) Tell the TCursor to "bind" itself. It, in turn, asks the
- TRelation to attach sufficient information to the TCursor to
- support first-next iteration over the records which match the
- query.
- (e) Retrieve the TTuples which constitute the answer to the query
- by calling TCursor.Next repeatedly until it says "I have no more
- tuples."
- (f) Steps (d) and (e) can be combined in the method TCursor.Each if
- appropriate.
-
- (4) The TRelation decides on a strategy for answering the query by "offering"
- the TCursor at the time of binding to each TAccessMethod attached to the
- TRelation until one of them "accepts" it. A TAccessMethod accepts a cursor
- if the query contains constraints against indexed fields of the view; i.e., can
- use the query to shortcut iteration over all records in the database. If no
- access method accepts, an "exhaustive" access method is used to iterate over
- the entire view.
-
- (5) TTuples are data structures which are capable of returning or setting the
- value of any domain of the relation in that tuple. This is best done by using
- a variant record or a pointer to the data, since data types can vary from one
- domain to the next. It would be nice to represent each individual value as an
- object, but in most realistic applications that results in too many records and
- a severe garbage collection problem. TTuple.Flush takes any changes made to
- values in the TTuple and writes them out to the corresponding record in the
- database.
-
- (6) TTuples are cached. This can either be done by making the TList of TTuples
- in the TRelation a TSortedList. When a query is posed which involves a unique
- index, the TSortedList is searched first (by the relevant TAccessMethod) for a
- TTuple with the right value; if it is there, no read from disk is performed and
- that TTuple is returned. If not, the read takes place and the resulting TTuple
- is placed in the TSortedList. If the query involves a non-unique index, a read
- from the view is always performed, but a new TTuple is constructed only if a
- matching one (according to some other, unique, index) is found in the
- TSortedList - otherwise, the one already cached is returned.
-
- (7) TTuples are garbage collected by maintaining a reference counter.
- TTuple.Grab increments the counter, TTuple.Release decrements it. If the count
- goes to zero as the result of TTuple.Release, the owning
- TRelation.ReleaseTuple(SELF) is called by the TTuple. If the TRelation is
- caching TTuples, the TTuple is freed and removed from the cache. If the
- TRelation contains all of its records in its TTuple list (i.e., caches
- everything or is not an InsideOut relation,) TRelation.ReleaseTuple does
- nothing. If you have functions returning a TTuple as value, it is also useful
- to have TTuple.ReleaseButDontFree, which will not scrap the TTuple before the
- caller has a chance to Grab it.
-
- This is a LOT of effort, but pays tremendous dividends:
-
- - In my most recent project, we had a single database which had relations
- derived from InsideOut, maintained in memory, derived from Finder flat files,
- and resident on a remote host; all were represented in a single scheme with the
- differences between these forms invisible to the application. (The key:
- subclass TRelation and TTuple wisely.) Put another way, this architecture
- makes InsideOut a special case.
-
- - The application need not be overly concerned with indexes. They are used
- wherever possible automatically.
-
- - It is possible to build on top of this structure to make the whole thing
- relationally complete; i.e., equivalent to SQL in expressive power. Joins, set
- difference, etc., are a matter of building smarter TCursors or TRelation
- subclasses ("Mr. Database, give me a TRelation which represents a Join of these
- two relations.")
-
- - One class - TTuple - represents all possible record types. Normally, one
- must construct a separate Pascal Record type for each InsideOut view.
-
- - Caching is automatic and better tailored to true performance gains than
- InsideOut's lower level block-oriented scheme. In particular, records which
- are referred to repeatedly but over long periods of time are retrieved faster
- using this architecture than by relying on InsideOut's optimizations. All you
- have to do is Grab it up front and not Release it until shutdown.
-
- It may seem that this is a lot of overhead to carry, but my experience has
- shown that not to be the case, either in terms of performance or code size.
- What you lose on the back end you more than make up for in the front in
- simplicity of the interface.
-
- Obviously, this link is already WAAAY too long and, thus, I will not go into
- more details. Suffice it to say that this architecture has been implemented
- and works well. If there is enough interest in the subject, I can follow up
- with a more in-depth article in Frameworks.
-
- Regards,
- Jeff Alger
- KPMG Peat Marwick
-
-